JavaScript30第二十九天要實作的專案是一個計時器網頁,可以讓使用者選擇要倒數的時間
Github 檔案位置:29 - Countdown Timer
網站的樣子
可以先看看最後的成果
第一步一樣是先選取好要操作的元素並加上監聽,接下來我們先實作倒數計時器的函式
const timerDisplay = document.querySelector('.display__time-left');
const endTime = document.querySelector('.display__end-time');
const buttons = document.querySelectorAll('[data-time]');
function timer(seconds) {
}
function startTimer() {
}
buttons.forEach(button => button.addEventListener('click', startTimer));
這裡以之前學過的 Date 獲取目前時間,加上要倒數的時間算出最後時間後,利用 setInterval 做每 1000 毫秒一次的倒數
備註:Date.now 取出時間的單位為毫秒,因此在 then 中要先將秒數乘上 1000
備註:setInterval 會回傳定時器編號給 countdown,以便後續做清除定時器,避免有多個定時器重複運行
let countdown;
function timer(seconds) {
  clearInterval(countdown);
  const now = Date.now();
  const then = now + seconds * 1000;
  countdown = setInterval(() => {
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    // check if we should stop it!
    if(secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
    console.log(secondsLeft);
  }, 1000);
}
function startTimer() {
  const seconds = parseInt(this.dataset.time);
  timer(seconds);
}

再來要實做的就是將資料渲染至畫面上了,要渲染的是每秒的即時時間倒數,以及最後倒數完的時間
我們要在一開始時就顯示最後停止時間,以及倒數的總時長,隨後就是跟著定時器每秒更新剩餘倒數時長即可
const timerDisplay = document.querySelector('.display__time-left');
const endTime = document.querySelector('.display__end-time');
function timer(seconds) {
  // ...
  const now = Date.now();
  const then = now + seconds * 1000;
  displayTimeLeft(seconds);
  displayEndTime(then);
  countdown = setInterval(() => {
    // ...
    displayTimeLeft(secondsLeft);
  }, 1000);
}
function displayTimeLeft(seconds) {
}
function displayEndTime(timestamp) {
}
先來處理 displayTimeLeft(seconds),這裡就以時間的總秒數做除和取餘數的運算,求出剩餘分鐘和剩餘秒數,再將值賦給 timerDisplay 和 document.title
備註:在秒數小於 10 時需在個位數前補零,以三元運算子實現
function displayTimeLeft(seconds) {
  const minutes = Math.floor(seconds / 60);
  const remainderSeconds = seconds % 60;
  const display = `${minutes}:${remainderSeconds < 10 ? '0' : '' }${remainderSeconds}`;
  document.title = display;
  timerDisplay.textContent = display;
}

再來處理 displayEndTime(timestamp),這裡以計算好的 then 目前時間建立 Date 物件,再分別取出十二小時制的小時和分鐘,並賦值至 endTime 中
備註:在分鐘數小於 10 時需在個位數前補零,以三元運算子實現
function displayEndTime(timestamp) {
  const end = new Date(timestamp);
  const hour = end.getHours();
  const adjustedHour = hour > 12 ? hour - 12 : hour;
  const minutes = end.getMinutes();
  endTime.textContent = `Be Back At ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`;
}

最後再讓我們加上自定義倒數時間的文字輸入框,這裡做的事情比較簡單,讀入輸入後轉換成秒,再呼叫計時器而已
document.customForm.addEventListener('submit', function(e) {
  e.preventDefault();
  const mins = this.minutes.value;
  console.log(mins);
  timer(mins * 60);
  this.reset();
});

const timerDisplay = document.querySelector('.display__time-left');
const endTime = document.querySelector('.display__end-time');
const buttons = document.querySelectorAll('[data-time]');
let countdown;
function timer(seconds) {
  clearInterval(countdown);
  const now = Date.now();
  const then = now + seconds * 1000;
  displayTimeLeft(seconds)
  displayEndTime(then)
  countdown = setInterval(() => {
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    // check if we should stop it!
    if(secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
    console.log(secondsLeft);
    displayTimeLeft(secondsLeft);
  }, 1000);
}
function displayTimeLeft(seconds) {
  const minutes = Math.floor(seconds / 60);
  const remainderSeconds = seconds % 60;
  const display = `${minutes}:${remainderSeconds < 10 ? '0' : '' }${remainderSeconds}`;
  document.title = display;
  timerDisplay.textContent = display;
}
function displayEndTime(timestamp) {
  const end = new Date(timestamp);
  const hour = end.getHours();
  const adjustedHour = hour > 12 ? hour - 12 : hour;
  const minutes = end.getMinutes();
  endTime.textContent = `Be Back At ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`;
}
function startTimer() {
  const seconds = parseInt(this.dataset.time);
  timer(seconds);
}
buttons.forEach(button => button.addEventListener('click', startTimer));
document.customForm.addEventListener('submit', function(e) {
  e.preventDefault();
  const mins = this.minutes.value;
  console.log(mins);
  timer(mins * 60);
  this.reset();
});
以上是第二十九天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
Vanilla JS Countdown Timer - #JavaScript30 29/30
[ Alex 宅幹嘛 ] ?? 深入淺出 Javascript30 快速導覽 | Day 29:Countdown Timer
MDN Web Docs